﻿using Grow.Json;
using Grow.Module.Service;
using Grow.Utils.Exceptions;

namespace Grow.EventBus.Cap.EventHandlerInvoker
{
    public class EventHandlerInvoker : IEventHandlerInvoker
    {
        private readonly IServiceContext _serviceContext;
        public EventHandlerInvoker(IServiceContext serviceContext)
        {
            _serviceContext = serviceContext;
        }
        public async Task ExecuteAsync(SubscriberEventDataDto subscriberEventDataDto, CancellationToken cancellationToken)
        {
            var serviceContext = _serviceContext.GetServiceContext();
            var jsonContext = serviceContext.GetRequiredService<IJsonContext>();
            var cancellationTokenContext = serviceContext.GetCancellationTokenContext();

            var eventDataType = Type.GetType(subscriberEventDataDto.EventDataType);
            if (eventDataType is null)
            {
                throw new GrowCheckException($"{nameof(eventDataType)} is not null");
            }

            var eventHandlerType = Type.GetType(subscriberEventDataDto.EventHandlerType);
            if (eventHandlerType is null)
            {
                throw new GrowCheckException($"{nameof(eventHandlerType)} is not null");
            }
            object eventHandler = serviceContext.GetRequiredService(eventHandlerType);

            var eventHeads = jsonContext.Deserialize<IDictionary<string, string>>(subscriberEventDataDto.EventHeads);
            if (eventHeads is null)
            {
                throw new GrowCheckException($"{nameof(eventHeads)} is not null");
            }

            var eventBody = jsonContext.Deserialize(subscriberEventDataDto.EventBody, Type.GetType(subscriberEventDataDto.EventDataType)!);
            if (eventBody is null)
            {
                throw new GrowCheckException($"{nameof(eventBody)} is not null");
            }
            var method = eventHandlerType.GetMethod("ExecuteAsync", new Type[] {
                eventDataType, typeof(IDictionary<string, string>),typeof(CancellationToken) });
            var task = (Task?)method!.Invoke(eventHandler, new object[] { eventBody, eventHeads, cancellationTokenContext.Token });
            await task!;
        }
    }
}
